/*
 * Copyright (c) 2024 OpenHiTLS. All rights reserved.
 * Licensed under the OpenHiTLS license.
 */
package org.openhitls.core;

import java.lang.ref.Cleaner;

/**
 * Base class for managing native resource lifecycle using Java's Cleaner API.
 * Ensures proper cleanup of native pointers when objects are garbage collected.
 *
 * <p>Subclasses should pass their native context pointer and a cleanup callback
 * to the constructor. The callback will be invoked when the object becomes
 * unreachable and is cleaned up by the garbage collector.</p>
 *
 * <p>Example usage:</p>
 * <pre>
 * public class MyNativeWrapper extends NativeResource {
 *     public MyNativeWrapper() {
 *         super(createNativeContext(), CryptoNative::freeMyContext);
 *     }
 * }
 * </pre>
 */
public abstract class NativeResource {
    private static final Cleaner CLEANER = Cleaner.create();

    protected final Cleaner.Cleanable cleanable;
    protected final long nativeContext;

    /**
     * Runnable that invokes the native cleanup callback.
     */
    protected static class CleanerRunnable implements Runnable {
        private final long nativeContext;
        private final FreeCallback freeCallback;

        CleanerRunnable(long nativeContext, FreeCallback freeCallback) {
            this.nativeContext = nativeContext;
            this.freeCallback = freeCallback;
        }

        @Override
        public void run() {
            if (nativeContext != 0) {
                freeCallback.freeNativeContext(nativeContext);
            }
        }
    }

    /**
     * Functional interface for native resource cleanup.
     */
    @FunctionalInterface
    protected interface FreeCallback {
        void freeNativeContext(long nativeContext);
    }

    /**
     * Creates a new NativeResource with automatic cleanup.
     *
     * @param nativeContext The native pointer/context to manage
     * @param freeCallback Callback to invoke for cleanup (e.g., CryptoNative::rsaFreeContext)
     */
    protected NativeResource(long nativeContext, FreeCallback freeCallback) {
        this.nativeContext = nativeContext;
        this.cleanable = CLEANER.register(this, new CleanerRunnable(nativeContext, freeCallback));
    }

    /**
     * Get the native context pointer.
     *
     * @return The native context pointer
     */
    public long getNativeContext() {
        return nativeContext;
    }

    /**
     * Explicitly clean up the native resource.
     * After calling this method, the native context should not be used.
     */
    public void close() {
        cleanable.clean();
    }
}
